
import java.awt.Color;
import java.io.*;
import java.net.*;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * <p>Title: Serveur.Serveur </p>
 *
 * <p>
 * 	Description: La classe Serveur est le processus java qui fait le serveur pour une salle
 * </p>
 *
 * <p>Copyright: (c) 2008 FSSIM</p>
 *
 * <p>Company: FSSImock</p>
 *
 * @author Antoine Farnault
 * @author Augustin Couette
 * @author Sebastien Oger
 * @author Aubry Pirian
 * @version 1.0
 */
public class Serveur {

	private static final int PORT = 32855; // le port d'ecoute
	public  static  Vector<Client> clients = new Vector<Client>(); // une liste de clients
	public static Vector<Table> tables = new Vector<Table>();
	public static String couleur = "000,000,000"; // couleur du serveur qd il ecrit dans le chat
	
	//++ Server properties
	private static String SEPARATOR = "	";
	private static final String SEPARATOR_PROTOCOL = ":";
	private static String PROPERTIES_FILE_PATH = "docs/archi/models/server_properties";
	// default properties
	private static final int DEFAULT_MAX_MEMBERS = 10000;
	private static final int DEFAULT_MAX_TABLES = 10000;
	private static final int DEFAULT_MAX_TABLES_PER_MEMBER = 5;
	// room properties
	private int maxMembers = DEFAULT_MAX_MEMBERS;
	private int maxTables = DEFAULT_MAX_TABLES;
	private int maxTablesPerMember=DEFAULT_MAX_TABLES_PER_MEMBER;
	//-- Server properties

	public static synchronized void insererJoueur(Client client) {
		clients.add(client);
	}
	
	/**
	 * Donne une couleur aleatoire
	 * @return String une couleur sous la forme xxx,yyy,zzz dans le code RGB
	 */
	public static String getRandomStringColor(){
		Random r = new Random();
		return ""+r.nextInt(255)+","+r.nextInt(255)+","+r.nextInt(255);
	}
	
	/**
	 * Enleve un client a la liste des clients
	 * @param client
	 */
	public synchronized void retirerClient(Client client) {
		clients.remove(client);
	}
	/**
	 * Un broadcast pour diffuser a tous les clients
	 * @param data
	 * @param from
	 */
	@SuppressWarnings("deprecation")
	public synchronized static void envoieATous(String data, String from,String salle,String couleur) {
		Iterator<Client> client = clients.iterator();
		Date d = new Date();
		String hours = ""+d.getHours();
		String minutes = ""+d.getMinutes();
		if(hours.length() < 2){
			hours = "0"+hours;
		}
		if(minutes.length() < 2){
			minutes = "0"+minutes;
		}
		while (client.hasNext()) {
			Client joueur = client.next();
			try {
				Protocol.snd_chat(joueur.pw,"("+hours+":"+minutes+") ", data, from,salle,couleur);
			} catch (ProtocolException e) {
				e.printStackTrace();
			}
		}
	}
	/**
	 * Le serveur met a jour la liste des joueurs de la salle(qd qlq un se connecte ou se deconnecte)
	 * @param clients
	 * @param monClient
	 */
	public static void updateConnectedJoueurs(Client monClient){
		
		try {
			Protocol.snd_joueur(monClient.pw, monClient.name, "connected",monClient.couleur);
		} catch (ProtocolException e1) {
			e1.printStackTrace();
		}
		
		// MAJ de la liste des joueurs
		Iterator<Client> client = Serveur.clients.iterator();
		while(client.hasNext()){
			Client joueur = client.next();
			try{
				Protocol.snd_joueur(joueur.pw, monClient.name, "connected", monClient.couleur);
				Protocol.snd_joueur(monClient.pw, joueur.name, "connected", joueur.couleur);
			}catch (Exception e) {
				e.printStackTrace();
			}
		}
	}

	/**
	 * Fonction qui lance le dé
	 * @return
	 */
	public static int lancerDe(){
		int lower = 1;
		int higher = 7;
		int random = (int)(Math.random() * (higher-lower)) + lower;
		return(random);
	}

	/**
	 * Récupère la liste des paramètres du serveur
	 * @throws IOException 
	 */
	private void retrieveProperties () throws IOException {
		// Reading file...
		File file = new File(PROPERTIES_FILE_PATH);
		BufferedReader br = new BufferedReader (new FileReader(file));
		String line;
		while ((line = br.readLine()) != null) {
//			System.err.println(line);
			// Parsing file...
			Pattern pattern = Pattern.compile("^(\\w*)"+SEPARATOR+"([A-Za-z0-9]*)$");
			Matcher matcher = pattern.matcher(line);
			if (matcher.find()) {
//				System.err.println("- Prop : "+matcher.group(1));
//				System.err.println("- Value : "+matcher.group(2));
				String propName = matcher.group(1);
				if (propName.equals("MAX_MEMBERS")) {
					this.maxMembers = Integer.parseInt(matcher.group(2));
				} else if (propName.equals("MAX_TABLES")) {
					this.maxTables = Integer.parseInt(matcher.group(2));
				} else if (propName.equals("MAX_TABLES_PER_MEMBER")) {
					this.maxTablesPerMember = Integer.parseInt(matcher.group(2));
				}
			}
		}
		br.close();
	}
	
	/**
	 * Enregistre les paramètres actuels du serveur
	 * @author Aubry Pirian
	 * @throws IOException
	 */
	private void saveProperties () throws IOException {
		File file = new File(PROPERTIES_FILE_PATH);
		BufferedWriter bw = new BufferedWriter (new FileWriter(file));
		bw.write("MAX_MEMBERS	"+this.maxMembers+"\n");
		bw.write("MAX_TABLES	"+this.maxTables+"\n");
		bw.write("MAX_TABLES_PER_MEMBER	"+this.maxTablesPerMember+"\n");
		bw.close();
	}

	/**
	 * Fonction main de lancement du serveur
	 * @param args
	 * @throws Exception
	 */
	public static void main(String[] args) throws Exception {
		//monServeur = new Serveur();
		System.out.println("Serveur en ecoute sur le port "+PORT);
		try {
			ServerSocket service = new ServerSocket(PORT);

			MAIN:while (true) {
				Socket connexion = service.accept();
				BufferedReader entree = new BufferedReader(new InputStreamReader(connexion.getInputStream()));
	
				HashMap<String, String> h = new HashMap<String, String>(); 
				String s;
				while((s=entree.readLine())!= null ){ 
					if (s.equals("FIN")){
						break;
					}
					try{
						Pattern pattern = Pattern.compile("^(\\w*)"+SEPARATOR_PROTOCOL+"(.*)$");
						Matcher matcher = pattern.matcher(s);
						if (matcher.find()) {
							String action = matcher.group(1);
							String values = matcher.group(2);
							h.put(action, values);
						} else {
							throw new ProtocolException("Non respect du protocol : "+s, h);
						}
					}catch(Exception e){
						System.err.println("Erreur de parsing");
						continue MAIN;
					}
				}
				if(h.get("type").equals("connect")){
					String pseudo = h.get("pseudo");
					Client monClient=new Client(connexion,pseudo, Serveur.getRandomStringColor());
					Protocol.snd_otp(monClient);
					// FIXME :: on demarre le thread meme si le rcv_otp est mauvais ...
	    			monClient.th = new ThreadServeur(connexion, pseudo, monClient);
					monClient.th.start();
				}
			}
		}
		catch (IOException e) {
			System.err.println("Erreur : " + e);
		}
	}
	
	/**
	 * prend une string de la forme xxx,yyy,zzz dans le code rgb
	 * @param couleur
	 * @return Color
	 */
	public static Color stringToColor(String couleur) {
		int r,g,b;
		String[] rgb = couleur.split(",");
		r = Integer.parseInt(rgb[0]);
		g = Integer.parseInt(rgb[1]);
		b = Integer.parseInt(rgb[2]);
		return new Color(r,g,b);
	}
	
	public static String colorToString(Color couleur) {
		return couleur.getRed()+","+couleur.getGreen()+","+couleur.getBlue();
	}

	public static void lancerJeu(Table t) {
		Serveur.envoieATous("Le jeu commence", "Serveur", t.nom,Serveur.couleur);
		t.nextTour();
	}
}












